package com.venusj.ipersistence.sqlSession;

import com.venusj.ipersistence.pojo.Configuration;

import java.lang.reflect.*;
import java.util.List;

/**
 * @author zhangjh
 * @date 2020/10/15
 * @desc
 */
public class DefaultSqlSession implements SqlSession{

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statemnetId, Object... params) {

        // Executor里面执行query方法
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        List query = null;
        try {
            query = simpleExecutor.query(configuration, configuration.getMappedStatementMap().get(statemnetId), params);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return query;
    }

    @Override
    public <T> T selectOne(String statemnetId, Object... params) {
        List<T> list = this.selectList(statemnetId, params);
        if(list.size() == 1)
        {
            return list.get(0);
        }
        else
        {
            throw new RuntimeException("查询出多个对象来了，或者对象为空");
        }
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        // 使用jdk proxy生成mapper对象
        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 根据不同情况调用Mapper中的方法
                // 利用反射获取class的全限定名和方法名(这里就是xml的命名空间和id要设置成全限定名和方法名一样的原因)
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();

                String statementId = className + "." + methodName;

                // args 等同于userDao.findByCondition(user);里面传的user参数
                // 获取被调用方法的返回值类型
                Type genericReturnType = method.getGenericReturnType();
                if(genericReturnType instanceof ParameterizedType)
                {
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                }
                return selectOne(statementId, args);
            }
        });
        return (T)proxyInstance;
    }
}
